/**
 * 基于Winston的统一日志系统
 *
 * 使用 winston-daily-rotate-file 实现日志按日期自动轮换和过期清理
 * 避免在MCP stdio模式下干扰协议通信
 */

import { existsSync, mkdirSync } from 'fs';
import { join } from 'path';
import winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
import { LOGS_DIR } from '../config';

// 日志配置
export const LOG_RETENTION_DAYS = parseInt(process.env.LOG_RETENTION_DAYS || '14', 10);

// 确保logs目录存在
if (!existsSync(LOGS_DIR)) {
  mkdirSync(LOGS_DIR, { recursive: true });
}

/**
 * 自定义日志格式
 */
const logFormat = winston.format.combine(
  winston.format.timestamp({
    format: 'YYYY-MM-DD HH:mm:ss.SSS',
  }),
  winston.format.errors({ stack: true }),
  winston.format.splat(),
  winston.format.json(),
  winston.format.printf(({ timestamp, level, message, stack, ...meta }) => {
    let log = `[${timestamp}] ${level.toUpperCase()}: ${message}`;

    // 添加错误堆栈
    if (stack) {
      log += `\n${stack}`;
    }

    // 添加额外元数据
    if (Object.keys(meta).length > 0) {
      log += `\n${JSON.stringify(meta, null, 2)}`;
    }

    return log;
  })
);

/**
 * 创建日志传输器配置
 */
function createDailyRotateTransports(): winston.transport[] {
  const transports: winston.transport[] = [];

  // 错误日志（按日期轮换）
  transports.push(
    new DailyRotateFile({
      filename: join(LOGS_DIR, 'error-%DATE%.log'),
      datePattern: 'YYYYMMDD',
      level: 'error',
      maxSize: '5m',
      maxFiles: `${LOG_RETENTION_DAYS}d`,
      format: logFormat,
      auditFile: join(LOGS_DIR, '.error-audit.json'),
    })
  );

  // 应用日志（按日期轮换）
  transports.push(
    new DailyRotateFile({
      filename: join(LOGS_DIR, 'app-%DATE%.log'),
      datePattern: 'YYYYMMDD',
      maxSize: '10m',
      maxFiles: `${LOG_RETENTION_DAYS}d`,
      format: logFormat,
      auditFile: join(LOGS_DIR, '.app-audit.json'),
    })
  );

  // 组合日志（按日期轮换）
  transports.push(
    new DailyRotateFile({
      filename: join(LOGS_DIR, 'combined-%DATE%.log'),
      datePattern: 'YYYYMMDD',
      maxSize: '10m',
      maxFiles: `${LOG_RETENTION_DAYS}d`,
      format: logFormat,
      auditFile: join(LOGS_DIR, '.combined-audit.json'),
    })
  );

  return transports;
}

/**
 * 创建异常处理传输器
 */
function createExceptionTransports(): winston.transport[] {
  return [
    new DailyRotateFile({
      filename: join(LOGS_DIR, 'exceptions-%DATE%.log'),
      datePattern: 'YYYYMMDD',
      maxSize: '5m',
      maxFiles: `${LOG_RETENTION_DAYS}d`,
      format: logFormat,
      auditFile: join(LOGS_DIR, '.exceptions-audit.json'),
    }),
  ];
}

/**
 * 创建rejection处理传输器
 */
function createRejectionTransports(): winston.transport[] {
  return [
    new DailyRotateFile({
      filename: join(LOGS_DIR, 'rejections-%DATE%.log'),
      datePattern: 'YYYYMMDD',
      maxSize: '5m',
      maxFiles: `${LOG_RETENTION_DAYS}d`,
      format: logFormat,
      auditFile: join(LOGS_DIR, '.rejections-audit.json'),
    }),
  ];
}

/**
 * 创建Winston日志器
 */
const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: logFormat,
  transports: createDailyRotateTransports(),
  exceptionHandlers: createExceptionTransports(),
  rejectionHandlers: createRejectionTransports(),
});

// 监听日志轮换事件
logger.transports.forEach(transport => {
  if (transport instanceof DailyRotateFile) {
    transport.on('rotate', (oldFilename, newFilename) => {
      logger.info('Log file rotated', { oldFilename, newFilename });
    });

    transport.on('archive', zipFilename => {
      logger.info('Log file archived', { zipFilename });
    });

    transport.on('logRemoved', removedFilename => {
      logger.info('Old log file removed', { removedFilename });
    });
  }
});

/**
 * 开发环境下可选择性启用控制台输出
 * 注意：仅在确定不是MCP stdio模式时使用
 */
export function enableConsoleLogging(enable: boolean = true): void {
  if (enable && !logger.transports.find(t => t instanceof winston.transports.Console)) {
    logger.add(
      new winston.transports.Console({
        level: 'debug',
        format: winston.format.combine(
          winston.format.colorize(),
          winston.format.simple(),
          winston.format.printf(({ timestamp, level, message }) => {
            return `[${timestamp}] ${level}: ${message}`;
          })
        ),
      })
    );
  } else if (!enable) {
    // 移除控制台传输器
    const consoleTransport = logger.transports.find(t => t instanceof winston.transports.Console);
    if (consoleTransport) {
      logger.remove(consoleTransport);
    }
  }
}

/**
 * 彻底禁用所有console方法，用于MCP stdio模式
 * 确保任何代码中的console调用都不会干扰MCP协议
 */
export function disableAllConsoleOutput(): void {
  const originalConsole = { ...console };
  const noop = (): void => {};

  // 保存原始console方法（用于恢复）
  (global as any).__originalConsole = originalConsole;

  // 将所有console方法替换为空操作
  console.log = noop;
  console.info = noop;
  console.warn = noop;
  console.error = noop;
  console.debug = noop;
  console.trace = noop;
  console.dir = noop;
  console.table = noop;
  console.group = noop;
  console.groupCollapsed = noop;
  console.groupEnd = noop;
  console.time = noop;
  console.timeEnd = noop;
  console.count = noop;
  console.countReset = noop;
  console.assert = noop;
  console.clear = noop;

  logger.info('All console methods disabled for MCP stdio mode');
}

/**
 * 将所有console方法重定向到stderr，用于MCP stdio模式
 * 允许调试输出而不影响MCP协议（stdout用于JSON-RPC通信）
 */
export function redirectConsoleToStderr(): void {
  const originalConsole = { ...console };

  // 保存原始console方法（用于恢复）
  (global as any).__originalConsole = originalConsole;

  // 创建格式化的stderr输出函数
  const createStderrLogger = (level: string) => {
    return (...args: any[]) => {
      const timestamp = new Date().toISOString();
      const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
      const message = args
        .map(arg => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)))
        .join(' ');

      // 直接写入stderr，不经过stdout
      process.stderr.write(`${prefix} ${message}\n`);
    };
  };

  // 将所有console方法重定向到stderr
  console.log = createStderrLogger('log');
  console.info = createStderrLogger('info');
  console.warn = createStderrLogger('warn');
  console.error = createStderrLogger('error');
  console.debug = createStderrLogger('debug');
  console.trace = (...args: any[]) => {
    const timestamp = new Date().toISOString();
    process.stderr.write(`[${timestamp}] [TRACE] ${args.join(' ')}\n`);
    // 获取调用栈
    const stack = new Error().stack?.split('\n').slice(2).join('\n');
    if (stack) {
      process.stderr.write(`${stack}\n`);
    }
  };

  // 其他console方法简化处理
  const simpleStderrLog = (...args: any[]) => {
    const message = args
      .map(arg => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)))
      .join(' ');
    process.stderr.write(`${message}\n`);
  };

  console.dir = simpleStderrLog;
  console.table = simpleStderrLog;
  console.group = simpleStderrLog;
  console.groupCollapsed = simpleStderrLog;
  console.groupEnd = () => process.stderr.write('\n');
  console.time = (label?: string) => {
    const timestamp = Date.now();
    (global as any).__timers = (global as any).__timers || {};
    (global as any).__timers[label || 'default'] = timestamp;
  };
  console.timeEnd = (label?: string) => {
    const timers = (global as any).__timers || {};
    const startTime = timers[label || 'default'];
    if (startTime) {
      const duration = Date.now() - startTime;
      process.stderr.write(`${label || 'default'}: ${duration}ms\n`);
      delete timers[label || 'default'];
    }
  };
  console.count = (() => {
    const counters: { [key: string]: number } = {};
    return (label = 'default') => {
      counters[label] = (counters[label] || 0) + 1;
      process.stderr.write(`${label}: ${counters[label]}\n`);
    };
  })();
  console.countReset = (label = 'default') => {
    // 重置计数器的逆辑需要与count共享状态，这里简化处理
    process.stderr.write(`${label}: 0\n`);
  };
  console.assert = (condition: boolean, ...args: any[]) => {
    if (!condition) {
      process.stderr.write(`Assertion failed: ${args.join(' ')}\n`);
    }
  };
  console.clear = () => {
    // 在stderr中输出清屏标识，但不实际清屏（避免影响调试）
    process.stderr.write('--- Console Clear ---\n');
  };

  logger.info('All console methods redirected to stderr for MCP stdio mode');
}

/**
 * 恢复console方法（主要用于测试）
 */
export function restoreConsoleOutput(): void {
  const originalConsole = (global as any).__originalConsole;
  if (originalConsole) {
    Object.assign(console, originalConsole);
    logger.info('Console methods restored');
  }
}

/**
 * 根据传输模式配置日志
 */
export function configureLogger(
  mode: 'stdio' | 'http' | 'streamable-http',
  options: {
    /** stdio模式下是否将console重定向到stderr（默认false，彻底禁用） */
    redirectToStderr?: boolean;
  } = {}
): void {
  logger.info('Configuring logger', { mode, options });

  switch (mode) {
    case 'stdio':
      // stdio模式：只使用文件日志，不使用控制台传输器
      enableConsoleLogging(false);

      if (options.redirectToStderr) {
        // 选项1：重定向到stderr（允许调试输出）
        redirectConsoleToStderr();
        logger.info('Logger configured for MCP stdio mode - console redirected to stderr');
      } else {
        // 选项2：彻底禁用（默认，最安全）
        disableAllConsoleOutput();
        logger.info('Logger configured for MCP stdio mode - all console output disabled');
      }
      break;

    case 'http':
    case 'streamable-http':
      // HTTP模式：可以安全使用控制台输出（用于开发调试）
      const isDevelopment = process.env.NODE_ENV === 'development';
      enableConsoleLogging(isDevelopment);
      logger.info('Logger configured for HTTP mode', { consoleEnabled: isDevelopment });
      break;
  }
}

/**
 * 创建子日志器（带前缀）
 */
export function createChildLogger(label: string): winston.Logger {
  return logger.child({ component: label });
}

/**
 * 标准化错误信息格式
 * 将任意错误对象转换为结构化的错误信息
 */
export function formatError(error: unknown): { error: string; stack?: string } {
  if (error instanceof Error) {
    return {
      error: error.message,
      stack: error.stack,
    };
  }

  return {
    error: String(error),
  };
}

/**
 * 创建标准化的错误日志上下文
 * 合并额外的上下文信息和格式化的错误信息
 */
export function createErrorLogContext(
  error: unknown,
  additionalContext?: Record<string, any>
): Record<string, any> {
  const formattedError = formatError(error);
  return {
    ...formattedError,
    ...additionalContext,
  };
}

// 对外导出日志器
export { logger };
export default logger;
